﻿// Decompiled with JetBrains decompiler
// Type: DnProcessSimulateCommands.SimulationRecorderAndPlayer.SimulationRecordingIntoXML
// Assembly: DnProcessSimulateCommands, Version=2402.0.0.890, Culture=neutral, PublicKeyToken=null
// MVID: A885D881-AEDF-447E-852A-6F13102E089C
// Assembly location: C:\Program Files\Tecnomatix_2402\eMPower\DotNetCommands\DnProcessSimulateCommands.dll

using EngineeringInternalExtension;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using System.Xml;
using Tecnomatix.Engineering;
using Tecnomatix.Engineering.PrivateImplementationDetails;
using Tecnomatix.Planning;


namespace DnProcessSimulateCommands.SimulationRecorderAndPlayer;

public class SimulationRecordingIntoXML
{
  private readonly string InfoTag = "Info";
  private readonly string IdTableTag = "IdTable";
  private readonly string IdMapping = nameof (IdMapping);
  private readonly string IsLineSimulationTag = "IsLineSimulation";
  private readonly string FileVersionTag = "FileVersion";
  private readonly string TimeTag = "Time";
  private readonly string AppearancesTag = "Appearances";
  private readonly string ConsumingOperationId = nameof (ConsumingOperationId);
  private readonly string CreateTag = "Create";
  private readonly string DeleteTag = "Delete";
  private readonly string AttachTag = "Attach";
  private readonly string DetachTag = "Detach";
  private readonly string InsertTag = "Insert";
  private readonly string ValAttribute = "Val";
  private readonly string UniqueAttribute = "Unique";
  private readonly string NameAttribute = "Name";
  private readonly string IdAttribute = "Id";
  private readonly string AttachmentParentIdAttribute = "AttachmentParentId";
  private readonly string ParentIdAttribute = "ParentId";
  private readonly string PmIdAttribute = "PmId";
  private readonly string JointsTag = "Joints";
  private readonly string JointTag = "Joint";
  private readonly string HumanJointsTag = "HumanJoints";
  private readonly string HumanJointTag = "HumanJoint";
  private readonly string SignalsTag = "Signals";
  private readonly string SignalTag = "Signal";
  private readonly string AttachmentsTag = "Attachments";
  private readonly string PrevValAttribute = "PrevVal";
  private readonly string LocationsTag = "Locations";
  private readonly string LocationTag = "Location";
  private readonly string HumansTag = "Humans";
  private readonly string HumanTag = "Human";
  private readonly string RX_Tag = "RX";
  private readonly string RY_Tag = "RY";
  private readonly string RZ_Tag = "RZ";
  private readonly string X_Tag = "X";
  private readonly string Y_Tag = "Y";
  private readonly string Z_Tag = "Z";
  private readonly string AbsoluteZero = $"0{NumberFormatInfo.CurrentInfo.NumberDecimalSeparator}0";
  private readonly TxMainFolder _appearancesFolder = ((IEnumerable<ITxMainFolder>) TxApplication.ActiveDocument.MainFolders).First<ITxMainFolder>((Func<ITxMainFolder, bool>) (x => x.FolderType == 9)) as TxMainFolder;
  private readonly TxPhysicalRoot _physicalRoot = TxApplication.ActiveDocument.PhysicalRoot;
  private readonly TxLogicalRoot _logicalRoot = TxApplication.ActiveDocument.LogicalRoot;
  private const double _uninitializedTime = -1.0;
  private TxSimulationPlayer m_simulationPlayer;
  private string _dir;
  private string _filePath;
  private XmlWriter _writer;
  private XmlDocument _xmlDoc;
  private XmlElement _docInfo;
  private XmlElement _idTableRootNode;
  private bool _xmlInit;
  private bool _isLineSimulation = TxEngineeringDataInternal.GlobalGetPartsMode() == 2;
  private double _lastTime = -1.0;
  private string _lastCreatedTime = string.Empty;
  private XmlElement _lastCreatedTimeElement;
  private int _uniqueIndex;
  private TxObjectList m_signals = new TxObjectList();
  private HashSet<ITxObject> m_appearances = new HashSet<ITxObject>();
  private Dictionary<string, string> m_mapPartPmIdToConsumingOperationPmId = new Dictionary<string, string>();
  private Dictionary<ITxPlcSignal, TxPlcValue> m_signalValues = new Dictionary<ITxPlcSignal, TxPlcValue>();
  private HashSet<ITxObject> _absoluteLocationData = new HashSet<ITxObject>();
  private Dictionary<string, string> _mapIdToPmId = new Dictionary<string, string>();
  private Dictionary<ITxHuman, Dictionary<string, double>> _humanJointData = new Dictionary<ITxHuman, Dictionary<string, double>>();
  private Dictionary<ITxDevice, TxObjectList> _drivingJoints = new Dictionary<ITxDevice, TxObjectList>();
  private Dictionary<ITxLocatableObject, ITxLocatableObject> _attachmentsData = new Dictionary<ITxLocatableObject, ITxLocatableObject>();
  private HashSet<ITxObject> m_appearancesForCreation = new HashSet<ITxObject>();
  private Dictionary<ITxObject, HashSet<ITxObject>> m_appearancesForInsertion = new Dictionary<ITxObject, HashSet<ITxObject>>();

  public bool Init(string fileFullPath)
  {
    bool flag = false;
    this._dir = Path.GetDirectoryName(fileFullPath);
    this._filePath = fileFullPath;
    if (!this._xmlInit)
    {
      try
      {
        Directory.CreateDirectory(this._dir);
        if (File.Exists(this._filePath))
          File.Delete(this._filePath);
        this._writer = XmlWriter.Create(this._filePath);
      }
      catch (Exception ex)
      {
        int num = (int) TxMessageBox.Show($"{SimulationRecorderAndPlayerStringTable.FAILED_TO_OPEN_FILE}\n{ex.Message}", SimulationRecorderAndPlayerStringTable.MESSAGEBOX_TITLE, MessageBoxButtons.OK, MessageBoxIcon.Hand);
        return false;
      }
      this._xmlDoc = new XmlDocument();
      this._docInfo = this._xmlDoc.CreateElement(this.InfoTag);
      this._docInfo.SetAttribute(this.IsLineSimulationTag, this._isLineSimulation.ToString().ToLower());
      this._xmlDoc.AppendChild((XmlNode) this._docInfo);
      this._docInfo.SetAttribute(this.FileVersionTag, Process.GetCurrentProcess().MainModule.FileVersionInfo.FileVersion);
      this._xmlDoc.AppendChild((XmlNode) this._docInfo);
      this._idTableRootNode = this.FindOrCreateElementUnderElement(this._docInfo, this.IdTableTag);
      this._xmlInit = true;
      this._uniqueIndex = 0;
      this.InitSignals();
      this.InitJoints();
      this.InitAppearances();
      this.InitAbsoluteLocationData();
      this.InitHumanJointData();
      this.InitAttachments();
      flag = true;
    }
    return flag;
  }

  public void Flush()
  {
    if (!this._xmlInit)
      return;
    this.FlushIdMap();
    this._xmlDoc.WriteTo(this._writer);
    this._writer.Flush();
    this._writer.Close();
    this._xmlInit = false;
    this.ClearData();
  }

  internal void FlushIdMap()
  {
    if (this._mapIdToPmId.Count > 0)
    {
      foreach (KeyValuePair<string, string> keyValuePair in this._mapIdToPmId)
      {
        XmlElement xmlElement = (XmlElement) this._idTableRootNode.AppendChild((XmlNode) this._xmlDoc.CreateElement(this.IdMapping));
        xmlElement.SetAttribute(this.IdAttribute, keyValuePair.Key);
        xmlElement.SetAttribute(this.PmIdAttribute, keyValuePair.Value);
      }
    }
    this._mapIdToPmId.Clear();
  }

  internal void ClearData()
  {
    this._lastTime = -1.0;
    this._lastCreatedTime = string.Empty;
    this._lastCreatedTimeElement = (XmlElement) null;
    this.ClearJointData();
    this.ClearAbsoluteLocationData();
    this.ClearSignals();
    this.ClearAppearances();
    this.ClearHumanData();
  }

  private XmlElement FindOrCreateElementUnderElement(XmlElement elem, string path)
  {
    XmlElement elementUnderElement = (XmlElement) elem.SelectSingleNode(path);
    if (elementUnderElement == null)
    {
      XmlElement element = this._xmlDoc.CreateElement(path);
      elementUnderElement = (XmlElement) elem.AppendChild((XmlNode) element);
    }
    return elementUnderElement;
  }

  private XmlElement FindOrCreateElementWithAttributeValueUnderElement(
    XmlElement elem,
    string elementTag,
    string attributeName,
    string AttributeValue)
  {
    XmlElement valueUnderElement = (XmlElement) elem.SelectSingleNode($"{elementTag}[@{attributeName}='{AttributeValue}']");
    if (valueUnderElement == null)
    {
      XmlElement element = this._xmlDoc.CreateElement(elementTag);
      valueUnderElement = (XmlElement) elem.AppendChild((XmlNode) element);
      valueUnderElement.SetAttribute(attributeName, AttributeValue);
    }
    return valueUnderElement;
  }

  private XmlElement FindOrCreateTimeElementUnderElement(XmlElement elem, string timeValue)
  {
    if (timeValue != this._lastCreatedTime)
    {
      this._lastCreatedTimeElement = this.FindOrCreateElementWithAttributeValueUnderElement(elem, this.TimeTag, this.ValAttribute, timeValue);
      this._lastCreatedTime = timeValue;
      TxSimulationPlayer simulationPlayer = this.m_simulationPlayer;
      this._lastTime = simulationPlayer != null ? simulationPlayer.CurrentTime : -1.0;
    }
    return this._lastCreatedTimeElement;
  }

  public void RegisterToSimulationEvents()
  {
    this.m_simulationPlayer = TxApplication.ActiveDocument.SimulationPlayer;
    this.RegisterCollectionEvents((ITxObjectCollection) this._appearancesFolder);
    this.RegisterCollectionEvents((ITxObjectCollection) this._physicalRoot);
    this.RegisterCollectionEvents((ITxObjectCollection) this._logicalRoot);
  }

  public void UnRegisterFromSimulationEvents()
  {
    this.UnregisterCollectionEvents((ITxObjectCollection) this._appearancesFolder);
    this.UnregisterCollectionEvents((ITxObjectCollection) this._physicalRoot);
    this.UnregisterCollectionEvents((ITxObjectCollection) this._logicalRoot);
  }

  private void RegisterAppearanceEvents(ITxObject obj)
  {
    this.RegisterCollectionEvents(obj as ITxObjectCollection);
  }

  private void UnregisterAppearanceEvents(ITxObject obj)
  {
    this.UnregisterCollectionEvents(obj as ITxObjectCollection);
  }

  private void RegisterCollectionEvents(ITxObjectCollection col)
  {
    if (col == null)
      return;
    col.ItemsAdded += new TxObjectCollection_ItemsAddedEventHandler(this.Collection_ItemsAdded);
  }

  private void UnregisterCollectionEvents(ITxObjectCollection col)
  {
    if (col == null)
      return;
    col.ItemsAdded -= new TxObjectCollection_ItemsAddedEventHandler(this.Collection_ItemsAdded);
  }

  private void RegisterDeletionEvent(ITxObject obj)
  {
    if (obj == null)
      return;
    obj.Deleted += new TxObject_DeletedEventHandler(this.TxObject_OnDeleted);
  }

  private void UnregisterDeletionEvent(ITxObject obj)
  {
    if (obj == null)
      return;
    obj.Deleted -= new TxObject_DeletedEventHandler(this.TxObject_OnDeleted);
  }

  private void EventHandlerBeginning() => this.FlushCreateAndInsertAppearancesIfNeeded();

  private void TxObject_OnDeleted(object sender, TxObject_DeletedEventArgs args)
  {
    if (this._lastTime > this.m_simulationPlayer.CurrentTime)
      return;
    this.EventHandlerBeginning();
    try
    {
      if (!(sender is ITxObject itxObject))
        return;
      this.CreateAppearanceElement(this.DeleteTag, itxObject);
      this.RemoveAppearanceData(itxObject);
      this.RemoveAbsoluteLocationData(itxObject);
      this.RemoveJointData(itxObject);
    }
    catch (Exception ex)
    {
      int num = (int) TxMessageBox.Show($"{ex.Message} \n{ex.StackTrace}", "SimulationRecorder Error", MessageBoxButtons.OK, MessageBoxIcon.Hand);
    }
  }

  private void Device_KinematicMoved(object sender, TxDevice_KinematicMovedEventArgs args)
  {
    if (this._lastTime > this.m_simulationPlayer.CurrentTime)
      return;
    this.EventHandlerBeginning();
    ITxDevice key = sender as ITxDevice;
    if (!this._drivingJoints.ContainsKey(key))
      this._drivingJoints.Add(key, key.DrivingJoints);
    foreach (ITxObject jntObj in (Collection<ITxObject>) this._drivingJoints[key])
      this.AddJointDataToXML((ITxObject) (jntObj as TxJoint).Device, jntObj);
  }

  private void LocatableObject_AbsoluteLocationChanged(
    object sender,
    TxLocatableObject_AbsoluteLocationChangedEventArgs args)
  {
    if (this._lastTime > this.m_simulationPlayer.CurrentTime)
      return;
    this.EventHandlerBeginning();
    this.AddLocatableObjectDataToXML((ITxObject) (sender as ITxLocatableObject));
  }

  private void Human_PostureModified(object sender, TxHuman_PostureModifiedEventArgs args)
  {
    if (this._lastTime > this.m_simulationPlayer.CurrentTime)
      return;
    this.EventHandlerBeginning();
    TxHumanJointData[] joints = (sender as TxHuman).GetPosture().Joints;
    ITxHuman key = sender as ITxHuman;
    Dictionary<string, double> humanJoints = new Dictionary<string, double>();
    foreach (TxHumanJointData txHumanJointData in joints)
    {
      if (this._humanJointData[key][txHumanJointData.Name] != txHumanJointData.Value)
      {
        this._humanJointData[key][txHumanJointData.Name] = txHumanJointData.Value;
        humanJoints.Add(txHumanJointData.Name, txHumanJointData.Value);
      }
    }
    if (humanJoints.Count <= 0)
      return;
    this.AddHumanObjectDataToXML((ITxObject) key, humanJoints);
  }

  private void SignalValueChanged(object sender, TxPlcSignal_ValueChangedEventArgs args)
  {
    if (this._lastTime > this.m_simulationPlayer.CurrentTime)
      return;
    this.EventHandlerBeginning();
    ITxPlcSignal itxPlcSignal = sender as ITxPlcSignal;
    this.AddSignalToXml(itxPlcSignal);
    this.m_signalValues[itxPlcSignal] = itxPlcSignal.Value;
  }

  private void Collection_ItemsAdded(object sender, TxObjectCollection_ItemsAddedEventArgs args)
  {
    if (this._lastTime > this.m_simulationPlayer.CurrentTime)
      return;
    this.EventHandlerBeginning();
    foreach (ITxObject itxObject in (Collection<ITxObject>) args.Items)
    {
      if (sender == this._physicalRoot || sender == this._logicalRoot || sender == this._appearancesFolder)
      {
        if (itxObject is ITxPartAppearance || TxEngineeringDataInternal.ObjectIsResourceAppearance(itxObject))
          this.AddAbsoluteLocationData(itxObject);
      }
      else if (sender is ITxPartAppearance parentObj && this._isLineSimulation)
        this.MarkInsertAppearance(itxObject, (ITxObject) parentObj);
    }
  }

  private void InitAppearances()
  {
    TxBIWLineServices txBiwLineServices = new TxBIWLineServices();
    foreach (ITxObject flowRootOperation in (Collection<ITxObject>) TxDocumentEx.PlcMaterialFlowRoot().GetMaterialFlowRootOperations())
    {
      foreach (ITxObject operationConsumedPart in (Collection<ITxObject>) txBiwLineServices.GetOperationConsumedParts(flowRootOperation))
      {
        string externalId = (operationConsumedPart as ITxPlanningObject).ProcessModelId.ExternalId;
        if (!this.m_mapPartPmIdToConsumingOperationPmId.ContainsKey(externalId))
          this.m_mapPartPmIdToConsumingOperationPmId.Add(externalId, TxEngineeringDataInternal.GetIdStringFromObject(flowRootOperation));
      }
    }
  }

  private void ClearAppearances()
  {
    this.m_mapPartPmIdToConsumingOperationPmId.Clear();
    HashSet<ITxObject> itxObjectSet = new HashSet<ITxObject>((IEnumerable<ITxObject>) this.m_appearances);
    foreach (ITxObject itxObject in itxObjectSet)
      this.RemoveAppearanceData(itxObject);
    this.m_appearances.Clear();
    itxObjectSet.Clear();
  }

  private void AddAppearanceData(ITxObject obj)
  {
    if (!this.m_appearances.Contains(obj))
    {
      this.m_appearances.Add(obj);
    }
    else
    {
      int num = (int) TxMessageBox.Show(obj.Name + " already in m_appearances!", "SimulationRecorder Error", MessageBoxButtons.OK, MessageBoxIcon.Hand);
    }
    this.RegisterDeletionEvent(obj);
  }

  private void RemoveAppearanceData(ITxObject obj)
  {
    this.UnregisterAppearanceEvents(obj);
    this.UnregisterDeletionEvent(obj);
    if (!this.m_appearances.Contains(obj))
      return;
    this.m_appearances.Remove(obj);
  }

  private void MarkCreateAppearance(ITxObject obj)
  {
    if (this.m_appearancesForCreation.Contains(obj))
      return;
    this.m_appearancesForCreation.Add(obj);
    this.RegisterAppearanceEvents(obj);
  }

  private void MarkInsertAppearance(ITxObject obj, ITxObject parentObj)
  {
    HashSet<ITxObject> itxObjectSet;
    if (!this.m_appearancesForInsertion.TryGetValue(obj, out itxObjectSet))
    {
      itxObjectSet = new HashSet<ITxObject>();
      this.m_appearancesForInsertion.Add(obj, itxObjectSet);
    }
    if (itxObjectSet.Contains(parentObj))
      return;
    itxObjectSet.Add(parentObj);
  }

  private void CreateAppearanceElement(
    string tag,
    ITxObject obj,
    XmlElement aTimeNode = null,
    ITxObject parentObj = null)
  {
    if (TxEngineeringDataInternal.GlobalGetPartsMode() != 2)
      return;
    XmlElement valueUnderElement = this.FindOrCreateElementWithAttributeValueUnderElement(this.FindOrCreateElementUnderElement(aTimeNode ?? this.CurrentSimulationTimeNode, this.AppearancesTag), tag, this.IdAttribute, obj.Id);
    if (TxFeatureManager.CheckFeature("SIMULATION_RECORDER_DEBUG"))
    {
      ++this._uniqueIndex;
      valueUnderElement.SetAttribute(this.UniqueAttribute, this._uniqueIndex.ToString());
      valueUnderElement.SetAttribute(this.NameAttribute, obj.Name);
    }
    if (parentObj != null)
      valueUnderElement.SetAttribute(this.ParentIdAttribute, parentObj.Id);
    string externalId;
    if (!this._mapIdToPmId.TryGetValue(obj.Id, out externalId))
    {
      if (obj is ITxPartAppearance itxPartAppearance)
      {
        ITxPlanningObject originPart = itxPartAppearance.OriginPart;
        if (originPart != null)
        {
          externalId = originPart.ProcessModelId.ExternalId;
          this._mapIdToPmId.Add(obj.Id, externalId);
          if (((Collection<ITxObject>) itxPartAppearance.OperationsToWhichAssigned).Count > 0)
          {
            this.m_mapPartPmIdToConsumingOperationPmId[externalId] = TxEngineeringDataInternal.GetIdStringFromObject(((Collection<ITxObject>) itxPartAppearance.OperationsToWhichAssigned)[0]);
            goto label_14;
          }
          goto label_14;
        }
      }
      if (TxEngineeringDataInternal.ObjectIsResourceAppearance(obj) && obj is ITxSkidAppearance itxSkidAppearance)
      {
        ITxPlanningObject originSkid = itxSkidAppearance.OriginSkid;
        if (originSkid != null && originSkid.IsObjectLoaded())
        {
          externalId = originSkid.ProcessModelId.ExternalId;
          this._mapIdToPmId.Add(obj.Id, externalId);
        }
      }
    }
label_14:
    string str;
    if (!string.IsNullOrEmpty(externalId) && this.m_mapPartPmIdToConsumingOperationPmId.TryGetValue(externalId, out str))
      valueUnderElement.SetAttribute(this.ConsumingOperationId, str);
    if (!(tag == this.CreateTag))
      return;
    this.AddJointData(obj, valueUnderElement);
    this.AddAbsoluteLocationData(obj, valueUnderElement);
  }

  private void FlushCreateAndInsertAppearancesIfNeeded()
  {
    if (!(this._lastCreatedTime != this.CurrentSimulationTime))
      return;
    Dictionary<ITxObject, HashSet<ITxObject>>.KeyCollection keys = this.m_appearancesForInsertion.Keys;
    foreach (ITxObject itxObject in keys)
    {
      if (this.m_appearances.Contains(itxObject))
      {
        HashSet<ITxObject> rootsOfInsertedObj = new HashSet<ITxObject>();
        this.GetAllAppearanceRoots(itxObject, itxObject, ref rootsOfInsertedObj);
        foreach (ITxObject parentObj in rootsOfInsertedObj)
          this.CreateAppearanceElement(this.InsertTag, itxObject, this.LastSimulationTimeNode, parentObj);
      }
    }
    HashSet<ITxObject> ProcessedNodesInHierarchy = new HashSet<ITxObject>();
    foreach (ITxObject itxObject in new HashSet<ITxObject>((IEnumerable<ITxObject>) this.m_appearancesForCreation))
    {
      if (!ProcessedNodesInHierarchy.Contains(itxObject))
      {
        ProcessedNodesInHierarchy.Add(itxObject);
        if (itxObject is ITxObjectCollection objectCollection)
        {
          foreach (ITxObject directDescendant in (Collection<ITxObject>) objectCollection.GetDirectDescendants((ITxTypeFilter) new TxNoTypeFilter()))
            this.RemoveDuplicateCreatedAppearanceOffspings(directDescendant, ref ProcessedNodesInHierarchy);
        }
      }
    }
    ProcessedNodesInHierarchy.Clear();
    foreach (ITxObject itxObject in this.m_appearancesForCreation)
    {
      if (!keys.Contains<ITxObject>(itxObject))
      {
        this.AddAppearanceData(itxObject);
        this.CreateAppearanceElement(this.CreateTag, itxObject, this.LastSimulationTimeNode);
      }
    }
    if (this.m_appearancesForCreation.Count == 0 && this.m_appearancesForInsertion.Count == 0)
    {
      XmlElement simulationTimeNode = this.CurrentSimulationTimeNode;
    }
    else
    {
      this.m_appearancesForCreation.Clear();
      this.m_appearancesForInsertion.Clear();
    }
  }

  private void RemoveDuplicateCreatedAppearanceOffspings(
    ITxObject node,
    ref HashSet<ITxObject> ProcessedNodesInHierarchy)
  {
    if (ProcessedNodesInHierarchy.Contains(node))
      return;
    ProcessedNodesInHierarchy.Add(node);
    if (this.m_appearancesForCreation.Contains(node))
      this.m_appearancesForCreation.Remove(node);
    if (!(node is ITxObjectCollection objectCollection))
      return;
    foreach (ITxObject directDescendant in (Collection<ITxObject>) objectCollection.GetDirectDescendants((ITxTypeFilter) new TxTypeFilter()))
      this.RemoveDuplicateCreatedAppearanceOffspings(directDescendant, ref ProcessedNodesInHierarchy);
  }

  private void GetAllAppearanceRoots(
    ITxObject insertedObjAncestor,
    ITxObject insertedObj,
    ref HashSet<ITxObject> rootsOfInsertedObj)
  {
    HashSet<ITxObject> itxObjectSet;
    if (this.m_appearancesForInsertion.TryGetValue(insertedObjAncestor, out itxObjectSet))
    {
      foreach (ITxObject insertedObjAncestor1 in itxObjectSet)
        this.GetAllAppearanceRoots(insertedObjAncestor1, insertedObjAncestor, ref rootsOfInsertedObj);
    }
    else
    {
      if (insertedObjAncestor == insertedObj || rootsOfInsertedObj.Contains(insertedObjAncestor))
        return;
      rootsOfInsertedObj.Add(insertedObjAncestor);
    }
  }

  private void InitJoints()
  {
    foreach (ITxObject allDescendant in (Collection<ITxObject>) TxApplication.ActiveDocument.PhysicalRoot.GetAllDescendants((ITxTypeFilter) new TxTypeFilter(new Type[1]
    {
      typeof (ITxDevice)
    }, new Type[0])))
      this.AddJointData(allDescendant);
  }

  private void ClearJointData()
  {
    foreach (ITxDevice key in this._drivingJoints.Keys)
      key.KinematicMoved -= new TxDevice_KinematicMovedEventHandler(this.Device_KinematicMoved);
    this._drivingJoints.Clear();
  }

  private void AddJointDataToXML(ITxObject deviceObj, ITxObject jntObj, XmlElement appearanceNode = null)
  {
    TxJoint txJoint = jntObj as TxJoint;
    XmlElement xmlElement = appearanceNode != null ? this.FindOrCreateElementWithAttributeValueUnderElement(appearanceNode, this.JointTag, this.IdAttribute, jntObj.Id) : this.FindOrCreateElementWithAttributeValueUnderElement(this.FindOrCreateElementUnderElement(this.CurrentSimulationTimeNode, this.JointsTag), this.JointTag, this.IdAttribute, jntObj.Id);
    string stringFromObject;
    if (!this._mapIdToPmId.TryGetValue(jntObj.Id, out stringFromObject))
    {
      stringFromObject = TxEngineeringDataInternal.GetIdStringFromObject(jntObj);
      this._mapIdToPmId.Add(jntObj.Id, stringFromObject);
    }
    if (TxFeatureManager.CheckFeature("SIMULATION_RECORDER_DEBUG"))
    {
      ++this._uniqueIndex;
      xmlElement.SetAttribute(this.UniqueAttribute, this._uniqueIndex.ToString());
      string str = $"{deviceObj.Name}.{jntObj.Name}";
      xmlElement.SetAttribute(this.NameAttribute, str);
    }
    string str1 = this.DoubleFormat(Math.Round(txJoint.CurrentValue, 4), 4);
    xmlElement.SetAttribute(this.ValAttribute, str1);
  }

  private void AddJointData(ITxObject obj, XmlElement appearanceNode = null)
  {
    if (!(obj is ITxDevice))
      return;
    ITxDevice key = obj as ITxDevice;
    key.KinematicMoved += new TxDevice_KinematicMovedEventHandler(this.Device_KinematicMoved);
    if (!this._drivingJoints.ContainsKey(key))
      this._drivingJoints.Add(key, key.DrivingJoints);
    foreach (ITxObject jntObj in (Collection<ITxObject>) this._drivingJoints[key])
    {
      TxJoint txJoint = jntObj as TxJoint;
      this.AddJointDataToXML(obj, jntObj, appearanceNode);
    }
  }

  private void RemoveJointData(ITxObject obj)
  {
    if (!(obj is ITxDevice))
      return;
    ITxDevice key = obj as ITxDevice;
    key.KinematicMoved -= new TxDevice_KinematicMovedEventHandler(this.Device_KinematicMoved);
    this._drivingJoints.Remove(key);
  }

  private void InitSignals()
  {
    this.m_signals = TxApplication.ActiveDocument.PlcProgramRoot.CurrentPlcProgram.GetSignals((ITxTypeFilter) new TxTypeFilter(typeof (ITxPlcSignal)));
    foreach (ITxPlcSignal signal in (Collection<ITxObject>) this.m_signals)
    {
      signal.ValueChanged += new TxPlcSignal_ValueChangedEventHandler(this.SignalValueChanged);
      this.m_signalValues.Add(signal, signal.Value);
      this.AddSignalToXml(signal);
    }
  }

  private void ClearSignals()
  {
    foreach (ITxPlcSignal signal in (Collection<ITxObject>) this.m_signals)
      signal.ValueChanged -= new TxPlcSignal_ValueChangedEventHandler(this.SignalValueChanged);
    ((Collection<ITxObject>) this.m_signals).Clear();
    this.m_signalValues.Clear();
  }

  private void AddSignalToXml(ITxPlcSignal signal)
  {
    XmlElement valueUnderElement = this.FindOrCreateElementWithAttributeValueUnderElement(this.FindOrCreateElementUnderElement(this.CurrentSimulationTimeNode, this.SignalsTag), this.SignalTag, this.IdAttribute, ((ITxObject) signal).Id);
    if (!this._mapIdToPmId.ContainsKey(((ITxObject) signal).Id))
      this._mapIdToPmId.Add(((ITxObject) signal).Id, TxEngineeringDataInternal.GetIdStringFromObject((ITxObject) signal));
    TxPlcSignalDataType dataType = signal.DataType;
    if (dataType == 6)
    {
      valueUnderElement.SetAttribute(this.PrevValAttribute, this.DoubleFormat((double) (float) this.m_signalValues[signal].GetValueByType((TxPlcHardwareType) dataType), 4));
      valueUnderElement.SetAttribute(this.ValAttribute, this.DoubleFormat((double) (float) signal.Value.GetValueByType((TxPlcHardwareType) dataType), 4));
    }
    else if (dataType == 11)
    {
      valueUnderElement.SetAttribute(this.PrevValAttribute, this.DoubleFormat((double) this.m_signalValues[signal].GetValueByType((TxPlcHardwareType) dataType), 4));
      valueUnderElement.SetAttribute(this.ValAttribute, this.DoubleFormat((double) signal.Value.GetValueByType((TxPlcHardwareType) dataType), 4));
    }
    else
    {
      valueUnderElement.SetAttribute(this.PrevValAttribute, this.m_signalValues[signal].GetValueByType((TxPlcHardwareType) dataType).ToString());
      valueUnderElement.SetAttribute(this.ValAttribute, signal.Value.GetValueByType((TxPlcHardwareType) dataType).ToString());
    }
  }

  private void InitAbsoluteLocationData()
  {
    foreach (ITxObject allDescendant in (Collection<ITxObject>) TxApplication.ActiveDocument.PhysicalRoot.GetAllDescendants((ITxTypeFilter) new TxTypeFilter(new Type[6]
    {
      typeof (ITxComponent),
      typeof (ITxSafetyObject),
      typeof (ITxLocationOperation),
      typeof (TxFrame),
      typeof (TxPartAppearance),
      typeof (ITxSkidAppearance)
    }, new Type[0])))
      this.AddAbsoluteLocationData(allDescendant);
  }

  private void InitAttachments()
  {
    foreach (ITxObject allDescendant in (Collection<ITxObject>) TxApplication.ActiveDocument.PhysicalRoot.GetAllDescendants((ITxTypeFilter) new TxTypeFilter(new Type[6]
    {
      typeof (ITxComponent),
      typeof (ITxSafetyObject),
      typeof (ITxLocationOperation),
      typeof (TxFrame),
      typeof (TxPartAppearance),
      typeof (ITxSkidAppearance)
    }, new Type[0])))
    {
      if (allDescendant is ITxLocatableObject locObj && locObj.AttachmentParent != null)
        this.AddAttachmentData(locObj, locObj.AttachmentParent);
    }
  }

  private void ClearAbsoluteLocationData()
  {
    foreach (ITxObject itxObject in this._absoluteLocationData)
    {
      if (itxObject is ITxLocatableObject)
      {
        ITxLocatableObject itxLocatableObject = itxObject as ITxLocatableObject;
        itxLocatableObject.AbsoluteLocationChanged -= new TxLocatableObject_AbsoluteLocationChangedEventHandler(this.LocatableObject_AbsoluteLocationChanged);
        itxLocatableObject.AttachmentChildAdded -= new TxLocatableObject_AttachmentChildAddedEventHandler(this.LocatableObject_AttachmentChildAdded);
        itxLocatableObject.AttachmentChildRemoved -= new TxLocatableObject_AttachmentChildRemovedEventHandler(this.LocatableObject_AttachmentChildRemoved);
      }
    }
    this._absoluteLocationData.Clear();
  }

  private void ClearAttachments()
  {
    foreach (ITxObject key in this._attachmentsData.Keys)
    {
      if (key is ITxLocatableObject)
      {
        ITxLocatableObject itxLocatableObject = key as ITxLocatableObject;
        itxLocatableObject.AttachmentChildAdded -= new TxLocatableObject_AttachmentChildAddedEventHandler(this.LocatableObject_AttachmentChildAdded);
        itxLocatableObject.AttachmentChildRemoved -= new TxLocatableObject_AttachmentChildRemovedEventHandler(this.LocatableObject_AttachmentChildRemoved);
      }
    }
    this._attachmentsData.Clear();
  }

  private bool AddAbsoluteLocationData(ITxObject obj, XmlElement appearanceNode = null)
  {
    bool flag = false;
    if (obj is ITxLocatableObject)
    {
      ITxLocatableObject itxLocatableObject = obj as ITxLocatableObject;
      if (itxLocatableObject.CanLocate())
      {
        if (!this._absoluteLocationData.Contains((ITxObject) itxLocatableObject))
        {
          itxLocatableObject.AbsoluteLocationChanged += new TxLocatableObject_AbsoluteLocationChangedEventHandler(this.LocatableObject_AbsoluteLocationChanged);
          this._absoluteLocationData.Add((ITxObject) itxLocatableObject);
          itxLocatableObject.AttachmentChildAdded += new TxLocatableObject_AttachmentChildAddedEventHandler(this.LocatableObject_AttachmentChildAdded);
          itxLocatableObject.AttachmentChildRemoved += new TxLocatableObject_AttachmentChildRemovedEventHandler(this.LocatableObject_AttachmentChildRemoved);
        }
        this.AddLocatableObjectDataToXML((ITxObject) itxLocatableObject, appearanceNode);
        flag = true;
      }
    }
    return flag;
  }

  private void AddAttachmentData(ITxLocatableObject locObj, ITxLocatableObject attachmentParent)
  {
    if (!this._attachmentsData.ContainsKey(locObj))
      this._attachmentsData.Add(locObj, attachmentParent);
    else
      this._attachmentsData[locObj] = attachmentParent;
    this.AddAttachmentDataToXML(this.AttachTag, locObj, attachmentParent);
  }

  private void AddAttachmentDataToXML(
    string tag,
    ITxLocatableObject locObj,
    ITxLocatableObject parent)
  {
    XmlElement valueUnderElement = this.FindOrCreateElementWithAttributeValueUnderElement(this.FindOrCreateElementUnderElement(this.CurrentSimulationTimeNode, this.AttachmentsTag), tag, this.IdAttribute, ((ITxObject) locObj).Id);
    if (!this._mapIdToPmId.ContainsKey(((ITxObject) locObj).Id))
      this._mapIdToPmId.Add(((ITxObject) locObj).Id, TxEngineeringDataInternal.GetIdStringFromObject((ITxObject) locObj));
    if (parent != null && !this._mapIdToPmId.ContainsKey(((ITxObject) parent).Id))
      this._mapIdToPmId.Add(((ITxObject) parent).Id, TxEngineeringDataInternal.GetIdStringFromObject((ITxObject) parent));
    if (parent == null)
      return;
    valueUnderElement.SetAttribute(this.AttachmentParentIdAttribute, ((ITxObject) parent).Id);
  }

  private void LocatableObject_AttachmentChildRemoved(
    object sender,
    TxLocatableObject_AttachmentChildRemovedEventArgs args)
  {
    ITxLocatableObject itxLocatableObject = sender as ITxLocatableObject;
    if (this._attachmentsData.ContainsKey(args.AttachmentChild) && this._attachmentsData[args.AttachmentChild].Equals((object) itxLocatableObject))
      this._attachmentsData.Remove(args.AttachmentChild);
    this.AddAttachmentDataToXML(this.DetachTag, args.AttachmentChild, (ITxLocatableObject) null);
  }

  private void LocatableObject_AttachmentChildAdded(
    object sender,
    TxLocatableObject_AttachmentChildAddedEventArgs args)
  {
    ITxLocatableObject parent = sender as ITxLocatableObject;
    if (!this._attachmentsData.ContainsKey(args.AttachmentChild))
      this._attachmentsData.Add(args.AttachmentChild, parent);
    else
      this._attachmentsData[args.AttachmentChild] = parent;
    this.AddAttachmentDataToXML(this.AttachTag, args.AttachmentChild, parent);
  }

  private void RemoveAbsoluteLocationData(ITxObject obj)
  {
    if (!(obj is ITxLocatableObject))
      return;
    ITxLocatableObject itxLocatableObject = obj as ITxLocatableObject;
    if (!this._absoluteLocationData.Contains((ITxObject) itxLocatableObject))
      return;
    itxLocatableObject.AbsoluteLocationChanged -= new TxLocatableObject_AbsoluteLocationChangedEventHandler(this.LocatableObject_AbsoluteLocationChanged);
    this._absoluteLocationData.Remove((ITxObject) itxLocatableObject);
    itxLocatableObject.AttachmentChildAdded -= new TxLocatableObject_AttachmentChildAddedEventHandler(this.LocatableObject_AttachmentChildAdded);
    itxLocatableObject.AttachmentChildRemoved -= new TxLocatableObject_AttachmentChildRemovedEventHandler(this.LocatableObject_AttachmentChildRemoved);
  }

  private void RemoveAttachmentData(ITxObject obj)
  {
    if (!(obj is ITxLocatableObject))
      return;
    ITxLocatableObject key = obj as ITxLocatableObject;
    if (!this._attachmentsData.ContainsKey(key))
      return;
    key.AttachmentChildAdded -= new TxLocatableObject_AttachmentChildAddedEventHandler(this.LocatableObject_AttachmentChildAdded);
    key.AttachmentChildRemoved -= new TxLocatableObject_AttachmentChildRemovedEventHandler(this.LocatableObject_AttachmentChildRemoved);
  }

  private void AddLocatableObjectDataToXML(ITxObject obj, XmlElement appearanceNode = null)
  {
    ITxLocatableObject itxLocatableObject = obj as ITxLocatableObject;
    bool flag = true;
    string key = string.Empty;
    if (obj is ITxPartAppearance itxPartAppearance)
    {
      ITxPlanningObject originPart = itxPartAppearance.OriginPart;
      if (originPart != null && this._isLineSimulation)
      {
        if (!this.m_appearances.Contains((ITxObject) itxPartAppearance) && !this.m_appearancesForCreation.Contains((ITxObject) itxPartAppearance))
        {
          this.MarkCreateAppearance((ITxObject) itxPartAppearance);
          flag = false;
          goto label_14;
        }
        key = originPart.ProcessModelId.ExternalId;
        if (((Collection<ITxObject>) itxPartAppearance.OperationsToWhichAssigned).Count > 0)
        {
          this.m_mapPartPmIdToConsumingOperationPmId[key] = TxEngineeringDataInternal.GetIdStringFromObject(((Collection<ITxObject>) itxPartAppearance.OperationsToWhichAssigned)[0]);
          goto label_14;
        }
        goto label_14;
      }
    }
    if (TxEngineeringDataInternal.ObjectIsResourceAppearance(obj) && obj is ITxSkidAppearance itxSkidAppearance)
    {
      ITxPlanningObject originSkid = itxSkidAppearance.OriginSkid;
      if (originSkid != null && originSkid.IsObjectLoaded())
      {
        if (!this.m_appearances.Contains((ITxObject) itxSkidAppearance))
        {
          this.AddAppearanceData((ITxObject) itxSkidAppearance);
          this.CreateAppearanceElement(this.CreateTag, (ITxObject) itxSkidAppearance);
        }
        key = originSkid.ProcessModelId.ExternalId;
        goto label_14;
      }
    }
    string stringFromObject;
    if (!this._mapIdToPmId.TryGetValue(obj.Id, out stringFromObject))
    {
      stringFromObject = TxEngineeringDataInternal.GetIdStringFromObject(obj);
      if (!string.IsNullOrEmpty(stringFromObject))
        this._mapIdToPmId.Add(obj.Id, stringFromObject);
    }
label_14:
    if (!string.IsNullOrEmpty(key) && !this._mapIdToPmId.ContainsKey(obj.Id))
      this._mapIdToPmId.Add(obj.Id, key);
    if (!flag)
      return;
    XmlElement xmlElement = appearanceNode != null ? this.FindOrCreateElementWithAttributeValueUnderElement(appearanceNode, this.LocationTag, this.IdAttribute, obj.Id) : this.FindOrCreateElementWithAttributeValueUnderElement(this.FindOrCreateElementUnderElement(this.CurrentSimulationTimeNode, this.LocationsTag), this.LocationTag, this.IdAttribute, obj.Id);
    if (TxFeatureManager.CheckFeature("SIMULATION_RECORDER_DEBUG"))
    {
      ++this._uniqueIndex;
      xmlElement.SetAttribute(this.UniqueAttribute, this._uniqueIndex.ToString());
      xmlElement.SetAttribute(this.NameAttribute, obj.Name);
    }
    TxVector translation = itxLocatableObject.AbsoluteLocation.Translation;
    string str1 = this.DoubleFormat(Math.Round(translation.X, 4), 4);
    xmlElement.SetAttribute(this.X_Tag, str1);
    string str2 = this.DoubleFormat(Math.Round(translation.Y, 4), 4);
    xmlElement.SetAttribute(this.Y_Tag, str2);
    string str3 = this.DoubleFormat(Math.Round(translation.Z, 4), 4);
    xmlElement.SetAttribute(this.Z_Tag, str3);
    TxVector rotationRpyXyz = itxLocatableObject.AbsoluteLocation.RotationRPY_XYZ;
    string str4 = this.DoubleFormat(Math.Round(rotationRpyXyz.X, 4), 4);
    xmlElement.SetAttribute(this.RX_Tag, str4);
    string str5 = this.DoubleFormat(Math.Round(rotationRpyXyz.Y, 4), 4);
    xmlElement.SetAttribute(this.RY_Tag, str5);
    string str6 = this.DoubleFormat(Math.Round(rotationRpyXyz.Z, 4), 4);
    xmlElement.SetAttribute(this.RZ_Tag, str6);
  }

  private void InitHumanJointData()
  {
    foreach (ITxObject allDescendant in (Collection<ITxObject>) TxApplication.ActiveDocument.PhysicalRoot.GetAllDescendants((ITxTypeFilter) new TxTypeFilter(new Type[1]
    {
      typeof (ITxHuman)
    }, new Type[0])))
      this.AddHumanJointData(allDescendant);
  }

  private void ClearHumanData()
  {
    foreach (ITxObject key1 in this._humanJointData.Keys)
    {
      if (key1 is ITxHuman)
      {
        ITxHuman key2 = key1 as ITxHuman;
        key2.PostureModified -= new TxHuman_PostureModifiedEventHandler(this.Human_PostureModified);
        this._humanJointData[key2].Clear();
      }
    }
    this._humanJointData.Clear();
  }

  private void AddHumanJointData(ITxObject obj, XmlElement appearanceNode = null)
  {
    if (!(obj is ITxHuman))
      return;
    ITxHuman key = obj as ITxHuman;
    key.PostureModified += new TxHuman_PostureModifiedEventHandler(this.Human_PostureModified);
    if (!(obj is TxHuman))
      return;
    TxHumanJointData[] joints = (obj as TxHuman).GetPosture().Joints;
    Dictionary<string, double> humanJoints = new Dictionary<string, double>();
    foreach (TxHumanJointData txHumanJointData in joints)
      humanJoints.Add(txHumanJointData.Name, txHumanJointData.Value);
    this._humanJointData.Add(key, humanJoints);
    this.AddHumanObjectDataToXML(obj, humanJoints);
  }

  private void AddHumanObjectDataToXML(ITxObject obj, Dictionary<string, double> humanJoints)
  {
    if (!this._mapIdToPmId.TryGetValue(obj.Id, out string _))
    {
      string stringFromObject = TxEngineeringDataInternal.GetIdStringFromObject(obj);
      this._mapIdToPmId.Add(obj.Id, stringFromObject);
    }
    XmlElement valueUnderElement = this.FindOrCreateElementWithAttributeValueUnderElement(this.FindOrCreateElementUnderElement(this.CurrentSimulationTimeNode, this.HumansTag), this.HumanTag, this.IdAttribute, obj.Id);
    valueUnderElement.SetAttribute(this.NameAttribute, obj.Name);
    XmlElement elementUnderElement = this.FindOrCreateElementUnderElement(valueUnderElement, this.HumanJointsTag);
    foreach (string key in humanJoints.Keys)
      this.FindOrCreateElementWithAttributeValueUnderElement(elementUnderElement, this.HumanJointTag, this.NameAttribute, key).SetAttribute(this.ValAttribute, this.DoubleFormat(Math.Round(humanJoints[key], 4), 4));
  }

  private string TimeToTruncatedString(double time)
  {
    string truncatedString = this.DoubleFormat(Math.Round(time, 4), 4);
    if (truncatedString == "0")
      truncatedString = this.AbsoluteZero;
    return truncatedString;
  }

  private string DoubleFormat(double num, int decimalDigit)
  {
    string format = "f" + decimalDigit.ToString();
    string str = num.ToString(format, (IFormatProvider) CultureInfo.InvariantCulture);
    if (str.Contains("."))
      str = str.TrimEnd('0');
    if (str.EndsWith("."))
      str = str.TrimEnd('.');
    return str;
  }

  private string CurrentSimulationTime
  {
    get
    {
      string currentSimulationTime = this.AbsoluteZero;
      if (this.m_simulationPlayer != null)
        currentSimulationTime = this.TimeToTruncatedString(this.m_simulationPlayer.CurrentTime);
      return currentSimulationTime;
    }
  }

  private XmlElement LastSimulationTimeNode
  {
    get
    {
      XmlElement simulationTimeNode = (XmlElement) null;
      if (!string.IsNullOrEmpty(this._lastCreatedTime))
        simulationTimeNode = this.FindOrCreateTimeElementUnderElement(this._docInfo, this._lastCreatedTime);
      return simulationTimeNode;
    }
  }

  private XmlElement CurrentSimulationTimeNode
  {
    get => this.FindOrCreateTimeElementUnderElement(this._docInfo, this.CurrentSimulationTime);
  }
}
